<?php
declare (strict_types = 1);

namespace app\admin;

use think\App;
use think\Exception;
use think\exception\ValidateException;
use think\facade\Log;
use think\helper\Str;
use think\Model;
use think\Request;
use think\Validate;

/**
 * 控制器基础类
 */
abstract class BaseController
{

    /**
     * 当前控制器所用到的模型容器
     */
    protected $models = [];

    /**
     * Request实例
     * @var \think\Request
     */
    protected $request;

    /**
     * 应用实例
     * @var \think\App
     */
    protected $app;

    /**
     * 是否批量验证
     * @var bool
     */
    protected $batchValidate = false;

    /**
     * 控制器中间件
     * @var array
     */
    protected $middleware = [];

    /**
     * 构造方法
     * @access public
     * @param  App  $app  应用对象
     */
    public function __construct(App $app)
    {

        $this->app     = $app;
        $this->request = $this->app->request;
        $this->initialize();
    }

    //该方法检测是否是来自后台首页的菜单点击
    private function initialize(){

        //当前请求路由
        $route = $this->getRealPathInfo();

        //后台首页路由
        $default_route = $this->getDefaultPathInfo();

        //如果请求的是默认首页(放行)
        if ($route !== $default_route){

            //获取referer
            $realReferer = request()->header('referer');
            $referer = (string) url('/admin')->domain(true);
            //如果不是来自首页菜单点击就跳转到后台首页
            if (is_null($realReferer) || !Str::startsWith($realReferer, $referer)){
                redirect((string) url($default_route))->send();
            }
        }
    }

    //当前请求真实路由
    private function getRealPathInfo(){
        return $this->request->completePathInfo();
    }
    //后台首页请求真实路由
    private function getDefaultPathInfo(){
        return $this->request->defaultPathInfo();
    }

    

    /**
     * 验证数据
     * @access protected
     * @param  array        $data     数据
     * @param  string|array $validate 验证器名或者验证规则数组
     * @param  array        $message  提示信息
     * @param  bool         $batch    是否批量验证
     * @return array|string|true
     * @throws ValidateException
     */
    protected function validate(array $data, $validate, array $message = [], $batch = false)
    {
        if (is_array($validate)) {
            $v = new Validate();
            $v->rule($validate);
        } else {
            if (strpos($validate, '.')) {
                // 支持场景
                list($validate, $scene) = explode('.', $validate);
            }
            $class = false !== strpos($validate, '\\') ? $validate : $this->app->parseClass('validate', $validate);
            $v     = new $class();
            if (!empty($scene)) {
                $v->scene($scene);
            }
        }

        $v->message($message);

        // 是否批量验证
        if ($batch || $this->batchValidate) {
            $v->batch(true);
        }

        return $v->failException(true)->check($data);
    }

    /**
     * 从模型容器中获取可用的模型
     * @param string $class
     * @param int|null $id
     * @param array $with
     * @param array $withCount
     * @return mixed
     * @throws Exception
     */
    protected function getModel(string $class, int $id = null, array $with=[], array $withCount = []){
        if (get_parent_class($class) !== Model::class &&
            get_parent_class(get_parent_class($class)) !== Model::class)
            throw new Exception('传参错误.');


        if (array_key_exists($class, $this->models) && empty($id)) {
            $model = $this->models[$class];
        }else{
            if (!is_null($id)){
                if(! $model = $class::with($with)->withCount($withCount)->find($id) )
                    abort(404, '页面不存在.');
            }else{
                $model = new $class();
            }
        }

        //获取权限规则
        if (!$model->isEmpty() && !$this->checkRule($model)){
            //记录日志
            Log::warning('您无权访问');
            abort(403, '您无权限.');
        }

        //缓存model 并返回model
        $this->models[$class] = $model;
        return $model;
    }

    /**
     * 检测权限规则
     * @param Model $model
     * @return bool
     */
    protected function checkRule(Model $model){
        $checkRule = request()->checkRule;
        if (isset($checkRule)){
            //当前控制器定义了是否关联用户模型
            $relateUser = isset($this->relateUser) && $this->relateUser;
            return  call_user_func_array($checkRule['callback'],[$model, $checkRule['rule'], $relateUser]);
        }
        return true;
    }

    /**
     * 批量操作规则检测
     * @param string $class
     * @param array $ids
     * @return bool
     * @throws Exception
     */
    protected function batchRule(string $class, array $ids){
        if (get_parent_class($class) !== Model::class &&
            get_parent_class(get_parent_class($class)) !== Model::class)
            throw new Exception('传参错误.');

        $checkRule = request()->checkRule;
        if (isset($checkRule)){
            //当前控制器定义了是否关联用户模型
            $relateUser = isset($this->relateUser) && $this->relateUser;
            $res =  call_user_func_array($checkRule['batchCallback'],[$class, $checkRule['rule'], $ids, $relateUser]);
            if (!$res){
                //记录日志
                Log::warning('您无权访问');
                abort(403, '您无权限.');
            }
        }
        return true;
    }

    /**
     * #根据权限规则生成列表查询条件
     * @return array|mixed
     */
    protected function ruleWhere(){
        $checkRule = request()->checkRule;

        if (isset($checkRule)){
            //当前控制器定义了是否关联用户模型
            $relateUser = isset($this->relateUser) && $this->relateUser;
            return  call_user_func_array($checkRule['listCallback'], [$checkRule['rule'], $relateUser]);
        }
        return [];
    }


}
